#include "mq_channel.hpp"
#include "mq_connection.hpp"
#include "mq_worker.hpp"
#include "muduo/net/TcpConnection.h"
#include <functional>
#include <google/protobuf/map.h>
#include <iostream>
#include <memory>
#include <string>
#include <format>
#include <chrono>
#include <thread>

void cb(const mqclient::ChannelPtr& channel, 
        const std::string& consumer_tag, 
        const proto::message::BasicProperties* bp, const std::string& body)
{
    LOG_DEBUG << std::format("\"consumer1\" consume a message: {}\n", body);
    channel->basicAck(bp->id());
}

int main(int argc, char* argv[])
{
    if(argc != 2) {
        std::cout << "usage: ./consume_client queue1\n";
        return 1;
    }
    // 1. 实例化异步工作线程池对象、连接对象
    mqclient::AsyncWorkerPtr worker = std::make_shared<mqclient::AsyncWorker>();
    worker->loopthread_.startLoop();
    mqclient::ConnectionPtr conn = std::make_shared<mqclient::Connection>("127.0.0.1", 8080, worker);
    // 2. 打开信道
    mqclient::ChannelPtr channel = conn->openChannel();
    // 3. 通过信道提供服务
    std::string exchange1 = "exchange1";
    std::string queue1 = "queue1";
    std::string queue2 = "queue2";
    //   a. 声明 exchange1, 广播交换
    google::protobuf::Map<std::string, std::string> empty_map;
    // channel->declareExchange(exchange1, proto::message::ExchangeType::FANOUT, true, false, empty_map);
    // channel->declareExchange(exchange1, proto::message::ExchangeType::DIRECT, true, false, empty_map);
    channel->declareExchange(exchange1, proto::message::ExchangeType::TOPIC, true, false, empty_map);

    //   b. 声明 queue1、queue2
    channel->declareQueue(queue1, true, false, false, empty_map);
    channel->declareQueue(queue2, true, false, false, empty_map);
    //   c. 绑定 exchange1-queue1/exchange1-queue2
    channel->queueBind(exchange1, queue1, "queue1");
    channel->queueBind(exchange1, queue2, "news.music.#");

    // 4. 订阅队列信息
    auto func = bind(cb, channel, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
    channel->basicConsume("consumer1", argv[1], false, func);

    while (1) std::this_thread::sleep_for(std::chrono::seconds(3));
    conn->closeChannel(channel);
    return 0;
}